Technical Note TN2079
Glyph Access Protocol

目次

Mac OS X に含まれるフォントには、Unicode の範囲に属さない多数のグリフが用意されています。Glyph Access Protocol は、これらのエンコード対象外グリフを、アプリケーションと入力メソッドで操作できるようにします。

このテクニカルノートでは、Text Services Manager、ATSUI、Cocoa を使用して上述のグリフをサポートする方法と、クリップボードを使用してデータ交換を行う方法について説明します。これらのサービスに対するサポートを組み込むアプリケーションおよび入力メソッドのデベロッパは、このテクニカルノートに目を通しておく必要があります。

[2003 年 5 月 6 日]






はじめに

Glyph Access Protocol により、アプリケーションと入力メソッドのデベロッパはエンコード対象外グリフをサポートできるようになります。この記事におけるエンコード対象外グリフとは、フォントに含まれているが、Unicode 3.2 規格の定義には含まれていないグリフを指します。つまり、このグリフは、標準の Unicode API を使ってもアクセスできず、フォントの Unicode マッピングテーブルに登録されていないということです。Mac OS X の多くのフォントは、エンコード対象外グリフを持っています。たとえばヒラギノ明朝 Pro W3 という日本語フォントには、そのようなグリフが 7000 以上含まれています。

図 1 に「き」と読む漢字の 5 つのバリエーションを示します。最も一般的なバリエーションであるこの 5 つは、Unicode 3.2 規格で U+559C、U+6199、U+6198、U+3402、U+6B56 と定義されています。

Unicode variants


図 1. Unicode で定義される「き」と読む漢字のバリエーション

しかし実際には、Mac OS X のヒラギノフォントには、「き」と読む漢字のバリエーションが 5 つではなく 8 つあります。図 2 に示すように、初めの 5 文字は Unicode で定義されています。しかし、残りの 3 つのグリフは Unicode で定義されておらず、グリフ ID によってのみ参照することができます。

Unicode variants


図 2. 「き」と読む漢字のすべてのバリエーション

Glyph Access Protocol により、デベロッパは次のことができます。

  1. フォントが持つ(エンコード対象外グリフを含む)すべてのグリフをサポートすること
  2. アプリケーションにおいて、クリップボードを使用したグリフデータの交換を可能にすること
  3. グリフを認識しないアプリケーションにグリフがコピーされたときに適切な対処を行う機能を提供すること
  4. Cocoa、ATSUI、MLTE を使用したリッチなテキストレイアウトをサポートするアプリケーションにおいて、エンコード対象外グリフのサポートを最小限の労力で追加できるようにすること
  5. ベース文字のテキストの編集、検索をはじめとする基本的なテキスト操作との一貫性を保つこと

Glyph Access Protocol では以下のサービスは提供されません。

  • クロスプラットフォームでのデータ交換。Glyph Access Protocol は、閉じたイメージングソリューションです。ほかのプラットフォームとデータを交換するファイルシステム、データベース、インターネットアプリケーションは、現在の実装の範囲外です。
  • Unicode 非対応アプリケーションのサポート。Glyph Access Protocol では、テキストのエンコーディングに Unicode の使用を想定しています。Unicode を認識しないアプリケーションは、このプロトコルを利用できません。

先頭に戻る

グリフの表現

エンコード対象外グリフをサポートするためには、グリフ ID を使ってグリフを指定する標準的な方法が必要となります。Glyph Access Protocol では、スタイル付きテキストを使用してグリフを指定します。アプリケーションと入力メソッドでは、追加のグリフスタイルをサポートすることによって、エンコード対象外グリフをサポートします。

Glyph Access Protocol では、基本 Unicode シーケンスグリフ属性修飾子によって各グリフが表されます。グリフ属性は、テキストの並びにおいて決して互いに重ならないようにする必要があります。

基本 Unicode シーケンスは、グリフを最も適切に表現する Unicode 文字の並びです。この基本 Unicode シーケンスは、編集や検索といった操作におけるテキストの動作を規定します。また、基本 Unicode シーケンスは、グリフ属性が失われたり、グリフ属性をサポートしないアプリケーションにデータが転送されたりしたときのテキストの代替動作を規定します。Unicode 規格で適切な基本 Unicode シーケンスが定義されていない場合、 (U+FFFD "REPLACEMENT CHARACTER") という文字が基本 Unicode シーケンスとして使用されます。

グリフ属性は、基本 Unicode シーケンスの表示に使用される実際のグリフを指定します。グリフは、フォントと、CID または GID によって識別されます。グリフ属性のデータ構造体 TSMGlyphInfo の定義については後述します。

先頭に戻る

Text Service Manager のプロトコル

入力メソッドは、テキスト入力イベントにおいて、オプションの kEventParamTextInputGlyphInfoArray パラメータを使用してアプリケーションにグリフを送ります。

アプリケーションが受け取った Carbon イベントに kEventParamTextInputGlyphInfoArray パラメータが含まれている場合、それはイベントに 1 つまたは複数のグリフが含まれていることを示します。 kEventParamTextInputGlyphInfoArray パラメータが含まれている可能性のある Carbon テキスト入力イベントは、次の 4 つです。

kEventTextInputUpdateActiveInputArea

kEventTextInputUnicodeForKeyEvent

kEventTextInputGetSelectedText

kEventTextInputUnicodeText

kEventTextInputGetSelectedText パラメータは TSMGlyphInfoArray です。TSMGlyphInfoArray は、次のように定義されています。

 TextServices.h

struct TSMGlyphInfoArray {

    ItemCount       numGlyphInfo;    // UInt32

    TSMGlyphInfo    glyphInfo[];

};



struct TSMGlyphInfo {

    CFRange         range;           // UTF16 オフセット(2 個の 32 ビット整数)

    ATSFontRef      fontRef;

    UInt16          collection;      // グリフコレクション

    UInt16          glyphID;         // GID(コレクションが 0 の場合)または CID

};

TSMGlyphInfo は、テキストの並びに埋め込まれている 1 つのグリフに対応し、そのグリフを表します。

TSMGlyphInfo.range は、UTF-16 におけるオフセットを使って、この TSMGlyphInfo を適用する TextInput テキストの範囲を指定します。それが、グリフの基本 Unicode シーケンスです。

TSMGlyphInfo.collection は、TSMGlyphInfo.glyphID の解釈方法を示します。このコレクションの値が kGlyphCollectionGID(ゼロ)の場合は、glyphID がグリフの ID を示します。ゼロ以外の値の場合は、その値が文字コレクションを示し、glyphID が CID を示します。TSMGlyphInfo.fontRef は、グリフの表示に使うフォントを示します。TSMGlyphInfo.collection は、fontRef において定義されるフォントの文字コレクションと一致する必要があります。コレクションが一致しない場合、TSMGlyphInfo は無効となり、無視する必要があります。

 CarbonEvents.h

enum {

    kGlyphCollectionGID         = 0;       // GlyphID はグリフ ID

    kGlyphCollectionAdobeCNS1   = 1;

    kGlyphCollectionAdobeGB1    = 2;

    kGlyphCollectionAdobeJapan1 = 3;

    kGlyphCollectionAdobeJapan2 = 4;

    kGlyphCollectionAdobeKorea1 = 5;

    kGlyphCollectionUnspecified = 0xFF;    // 指定なし

                                           // glyphID は CID

};


TSMGlyphInfo.glyphID の値がゼロで、グリフを示さない場合、テキストの範囲に対するフォントのアタッチには TSMGlyphInfo が使用されます。この場合、TSMGlyphInfo.fontRef は、TSMGlyphInfo.range によって指定されるテキストの範囲を表示する際に使うべきフォントを指定します。これは、Unicode の私用領域の文字を使用する場合に役立ちます。Wingdings や、Windows のベースの pi フォント(シンボルフォント)は、このような文字の例です。TSMGlyphInfo.glyphID がゼロの場合、TSMGlyphInfo.collection もゼロでなければならず、アプリケーションはその値を無視する必要があります。

入力ストリームでのフォントの指定は、結果として混乱を招くユーザインタフェースとなる可能性があるので、入力メソッドのデベロッパはこの属性を慎重に使用する必要があります。この属性は、絶対に必要な場合にだけ使用するべきです。妥当な例としては、エンコード対象グリフの入力と、私用領域に属する文字の表示フォントの指定があります。

入力メソッドからテキストを受け取ったアプリケーションでは、そのテキストを内部表現に自由に変換できます。ただし、アプリケーションが kEventTextInputGetSelectedText に応答するときは、データを元の TSMGlyphInfo 形式に変換し戻す必要があります。

glyphID は、基本文字シーケンスから同じ結果が得られる同等の OpenType フィーチャまたは AAT フィーチャに変換できます。変換する場合には、たとえ OpenType または AAT が同じ文字コレクションを持っていても、これらのテーブルがフォント間で共通であると想定するべきではありません。CID は、同じ文字コレクションに属するすべてのフォントについて同一であることが保証されているので、一般的に OpenType または AAT のフィーチャよりも強力です。

AAT フィーチャについては、http://developer.apple.com/fonts/ に解説があります。

ATSFontRef は、FMGetFontFromATSFontRef() を呼び出すことによって、ATSUFontID に変換することができます。

先頭に戻る

TSMDocument のグリフ入力の有効化

エンコード対象外グリフの入力をサポートするアプリケーションでは、各 TSMDocument の kTSMDocumentPropertySupportGlyphInfo プロパティを設定することによって、そのことを Text Service Manager と入力メソッドに通知する必要があります。

 TextServices.h

enum { kTSMDocumentPropertySupportGlyphInfo = 'dpgi' };



extern OSStatus TSMSetDocumentProperty(

    TSMDocumentID    docID,

    OSType           propertyTag,

    UInt32           propertySize,

    void *           propertyData);



extern OSStatus TSMGetDocumentProperty(

    TSMDocumentID    docID,

    OSType           propertyTag,

    UInt32           bufferSize,

    UInt32 *         actualSize,

    void *           propertyBuffer);


入力メソッドで、現在の TSMDocument によってグリフ入力がサポートされているかどうかを知るには、kTSMDocumentPropertySupportGlyphInfo プロパティを調べる必要があります。

注記:
Mac OS X 10.2 における「ことえり」と文字パレットでは kTSMDocumentPropertySupportGlyphInfo プロパティが無視されますが、今後のバージョンでは、このプロパティがテストされてからユーザインタフェースでのグリフ入力が有効にされるようになる予定です。

先頭に戻る

ATSUI と エンコード対象外グリフ

ATSUI では、エンコード対象外グリフは、Text Services Manager プロトコルと同じような方法で表現されます。それぞれの TSMGlyphInfo 構造体が、以下に示すデータ構造体に変換され、ATSUI 属性としてスタイルランにアタッチされます。

GlyphInfo.glyphID がゼロでない場合、つまり、GlyphInfo.collectionGlyphInfo.glyphID に有効なデータが含まれている場合、これらの 2 つのフィールドは、kATSUGlyphSelectorTag がアタッチされた ATSUGlyphSelector に変換されます。

GlyphInfo.fontRefkATSFontRefUnspecified(ゼロ)でない場合は、kATSUFontTag がアタッチされた ATSUFontID に変換されます。

 ATSUnicode.h

enum { kATSUGlyphSelectorTag = 287L };    // ATSUGlyphSelector 型

enum { kATSUFontTag = 261L };             // ATSUFontID 型



struct ATSUGlyphSelector {                // 32 ビットセレクタ

    UInt16    collection;                 // kGlyphCollectionXXX enum

    UInt16    glyphID;                    // GID(collection = 0 時)または CID

};


ATSUI については http://developer.apple.com/techpubs/macosx/Carbon/text/ATSUI/atsui.html に説明があります。

先頭に戻る

Cocoa とエンコード対象外グリフ

Cocoa における Glyph Access のサポートについては、以下の場所に説明があります。

NSGlyphInfo:
http://developer.apple.com/techpubs/macosx/Cocoa/Reference/ApplicationKit/ObjC_classic/Classes/NSGlyphInfo.html

NSTextView では、テキストへのエンコード対象外グリフの入力を可能にする以下のメソッドが提供されます。各メソッドの詳細については、関連ドキュメントを参照してください。
- (BOOL)acceptsGlyphInfo;
http://developer.apple.com/techpubs/macosx/Cocoa/Reference/ApplicationKit/ObjC_classic/Classes/NSTextView.html#BBCBBGIG
- (void)setAcceptsGlyphInfo:(BOOL)flag;
http://developer.apple.com/techpubs/macosx/Cocoa/Reference/ApplicationKit/ObjC_classic/Classes/NSTextView.html#BBCIHACG


Mac OS X 10.2 以降の TextEdit アプリケーションでは、Glyph Access Protocol がサポートされています。TextEdit を使えば、エンコード対象外グリフの入力、コピー、貼り付け、保存が可能です。

先頭に戻る

Scrap Type

ATSUI の標準の表現は、クリップボード経由でテキストを交換するのに使用します。“utxt”は、TSM プロトコルと同じ基本文字シーケンスを持つ必要があります。“ustl”は、上述の ATSUI 属性を持ちます。

先頭に戻る

エンコード対象外グリフ編集のガイドライン

一般的に、グリフ属性を持つテキストの性質は、基本 Unicode シーケンスからグリフ属性を引いたものの性質と同じです。どの部分であれ基本の Unicode シーケンスが変更された場合、グリフ属性を削除する必要があります。

たとえば、基本 Unicode シーケンス “1”(いち)、“/”(スラッシュ)、“1”(いち)、“0”(ゼロ)、“0”(ゼロ)からなる特別なグリフ“1/100”(100 分の 1 または CID の位置 9824)があるとします。シーケンスの末尾にカレットを置いて削除キーを 1 回押すと、基本 Unicode シーケンスは、“1”(いち)、“/”(スラッシュ)、“1”(いち)、“0”(ゼロ)になります。基本 Unicode シーケンスが“1/10”になったら、グリフ“1/100”(100 分の 1)を用いてこのシーケンスを表現するべきではありません。基本 Unicode シーケンスの内容に変更を加えた場合も、同じです。たとえば、“1/100”が“1/200”になる場合などです。

 

Deleting a character

図 1. 編集時の動作とグリフ属性ワード


通常のスタイルとは異なり、グリフ属性の対象範囲は、基本 Unicode シーケンスの後にテキストが挿入されたときに広がってはなりません。たとえば、グリフ“1/100”(100 分の 1)の後に“0”(ゼロ)が入力された場合、このテキストは、グリフ“1/100”(100 分の 1)とその後に続くグリフ“0”(ゼロ)で表されます。

 

Typing a character

図 2. 編集時の動作とグリフ属性ワード


ユーザがグリフのフォントを、グリフ属性と矛盾するフォントに変更しようとしたとき、アプリケーションでは、矛盾をユーザに通知するか、または単にテキストのレンダリング時にグリフ属性を無視するかを選ぶことができます。

先頭に戻る

要約

Mac OS X のフォントには、標準 Unicode API を使ってもアクセスできないグリフが多数含まれています。Glyph Access Protocol は、これらのエンコード対象外グリフにアクセスしたり、入力メソッドやほかのアプリケーションとの間で交換したりするための標準の仕組みを定義します。

先頭に戻る

 

参考文献

Text Services Manager
http://developer.apple.com/techpubs/macosx/Carbon/text/TextServicesManager/textservicesmgr.html

Unicode Imaging (ATSUI) のための Apple Type Service
http://developer.apple.com/techpubs/macosx/Carbon/text/ATSUI/atsui.html

Carbon Event Manager
http://developer.apple.com/techpubs/macosx/Carbon/oss/CarbonEventManager/carboneventmanager.html

フォントとツール
http://developer.apple.com/fonts/

Adobe-Japan 文字コレクション
CID キーフォント用 Adobe-Japan1-4 文字コレクション (PDF)
CID キーフォント用 Adobe-Japan1-5 文字コレクション (PDF)

先頭に戻る